from skimage.measure import compare_ssim
from datetime import datetime
from threading import Thread  # 导入线程函数
from time import sleep  # 导入时间休眠函数
import argparse
import imutils
import cv2
import time
#import os
import winsound
import numpy as np
#from goto import with_goto//本来有用到的，但是考虑到严谨性，哈哈还是算了~

'初始化SSIM模型安全值'
def InitializeSSIM():
    #调用笔记本内置摄像头，所以参数为0，如果有其他的摄像头可以调整参数为1，2
    cap=cv2.VideoCapture(0)

    #从摄像头读取图片
    sucess,InitializeSSIMA=cap.read()
    gray=cv2.cvtColor(InitializeSSIMA,cv2.COLOR_BGR2GRAY)
    cv2.imwrite("InitializeSSIMA.png",InitializeSSIMA)
    imageA = cv2.bilateralFilter(InitializeSSIMA,9,75,75)
    grayA = cv2.cvtColor(InitializeSSIMA, cv2.COLOR_BGR2GRAY)

    SSIM_All = []

    for i in range(5):
        i=0
        i=i+1
        sucess,InitializeSSIMB=cap.read()
        time.sleep(0.5)
        cv2.imwrite("InitializeSSIMB.png",InitializeSSIMB)
        grayB = cv2.cvtColor(InitializeSSIMB, cv2.COLOR_BGR2GRAY)
        imageB = cv2.bilateralFilter(InitializeSSIMB,9,75,75)
        #计算两者之间的结构相似性指数
        #图像，确保返回差异图像
        (score, diff) = compare_ssim(grayA, grayB, full=True)
        diff = (diff * 255).astype("uint8")
        print("正在初始化/更新模型数据，请不要移动摄像头...ssim: {}".format(score))
        
        SSIM_All.append(score)
        
    print("\n模型数据更新成功！！！\n\nALL_SSIM: ", SSIM_All)

    SSIM_AVR = ((float(SSIM_All[0])+float(SSIM_All[1])+\
                float(SSIM_All[2])+float(SSIM_All[3])+\
                float(SSIM_All[4]))/5)-0.001

    print('当前的ssim为：',SSIM_AVR)
    cv2.destroyAllWindows()
    return SSIM_AVR

def Camera(n):  # 初始化摄像头获取第一张图作为模型/选择摄像头

    #InitializeSSIM()
    SSIM_AVR = InitializeSSIM()
    #调用笔记本内置摄像头，所以参数为0，如果有其他的摄像头可以调整参数为1，2
    cap=cv2.VideoCapture(0)

    #调用时间直接复制：print (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    #初始化获取第A张图
    sucess,imageA=cap.read()
    #写入A
    cv2.imwrite("1.png",imageA)
    # 将图像转换为灰度
    grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
    #转为灰度图片
    gray=cv2.cvtColor(imageA,cv2.COLOR_BGR2GRAY)
    #降噪A
    imageA = cv2.medianBlur(imageA,5)
    t2 = Thread(target=Ring)  # 定义线程t2，线程任务为调用task2函数，task2函数无参数

    while True:
        
        #当前时间
        a = int(time.time())
        c = datetime.fromtimestamp(a+43200).strftime('%S')    #格式转换
        c=int (c)
        
        '''/////////////'''
        #按时间间隔更新A,每59S也要更新SSIM的AVR
        '''/////////////'''
        if c == 59:
            #更新获取第A张图
            sucess,imageA=cap.read()
            #写入A
            cv2.imwrite("1.png",imageA)
            # 将图像转换为灰度
            grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
            #转为灰度图片
            gray=cv2.cvtColor(imageA,cv2.COLOR_BGR2GRAY)
            #降噪A
            imageA = cv2.medianBlur(imageA,5)
            
            print('开始更新摄像头模型数据..请不要惊慌^_^')
            #cv2.waitKey(0)
            #关闭摄像头
            cap.release()
            SSIM_AVR = InitializeSSIM()
            
            '''//这一段是补偿代码！也就是重启由于初始化SSIM的时候冲突的数据//'''
            #调用笔记本内置摄像头，所以参数为0，如果有其他的摄像头可以调整参数为1，2
            cap=cv2.VideoCapture(0)

            #调用时间直接复制：print (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
            #初始化获取第A张图
            sucess,imageA=cap.read()
            #写入A
            cv2.imwrite("1.png",imageA)
            # 将图像转换为灰度
            grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
            #转为灰度图片
            gray=cv2.cvtColor(imageA,cv2.COLOR_BGR2GRAY)
            #降噪A
            imageA = cv2.medianBlur(imageA,5)
            t2 = Thread(target=Ring)  # 定义线程t2，线程任务为调用task2函数，task2函数无参数
            '''//这一段是补偿代码！也就是重启由于初始化SSIM的时候冲突的数据//'''
            
        #从摄像头读取图片B
        sucess,imageB=cap.read()
        #转为灰度图片
        gray=cv2.cvtColor(imageB,cv2.COLOR_BGR2GRAY)

        #显示摄像头，背景是灰度,打印时间。
        cv2.putText(gray,(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())),
                    (20,400),cv2.FONT_HERSHEY_SIMPLEX,0.7,(255,255,255), 1,
                    cv2.LINE_AA)
        cv2.imshow("Real time state",gray)
        
        #保持画面的持续。
        k=cv2.waitKey(1)
        if k == 27:
            #通过esc键退出摄像
            cv2.destroyAllWindows()
            break
          
        #不断地判断是否不符合。
        elif __name__ == '__main__':

             time.sleep(0.5)
             cv2.imwrite("2.png",imageB)
             #  cv2.destroyAllWindows()
             #  break

             # 将图像转换为灰度
             grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

             #计算两者之间的结构相似性指数
             #图像，确保返回差异图像
             (score, diff) = compare_ssim(grayA, grayB, full=True)
             diff = (diff * 255).astype("uint8")

             #显示初始化的模型与当前图像的SSIM：
             #print("与初始化模型的匹配值: {}".format(score))
             
             t2 = Thread(target=Ring)  # 定义线程t2，线程任务为调用task2函数，task2函数无参数

             if score<=SSIM_AVR:
                 t2.start()  # 开始运行t2线程
                 
             else:
                 print('安全')
             
             #将差分图像设为阈值，然后查找等高线
             #获取两个不同输入图像的区域
             thresh = cv2.threshold(diff, 255, 255,
                     cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
             cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                     cv2.CHAIN_APPROX_SIMPLE)
             cnts = imutils.grab_contours(cnts)

             #画框框
             for c in cnts:
                     #计算轮廓的边界框，然后绘制
                     #两个输入图像上的边界框，表示两个
                     #图像不同
                     (x, y, w, h) = cv2.boundingRect(c)
                     #cv2.rectangle(imageA, (x, y), (x + w, y + h), (0, 0, 255), 2)
                     cv2.rectangle(imageB, (x, y), (x + w, y + h), (0, 255,0), 2)

             #图像降噪处理
             imageB = cv2.medianBlur(imageB,5)

             
             #显示输出图像
             #cv2.imshow("Original", imageA)

             # 显示SSIM值
             cv2.putText(imageB, ("SSIM: {}".format(score)),
                         (20, 400), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 1,
                         cv2.LINE_AA)
             cv2.imshow("Modified", imageB)
             cv2.imshow("Diff", diff)
             cv2.imshow("Thresh", thresh)
             
    cv2.waitKey(0)
    #关闭摄像头
    #cap.release()

def Ring():  # 定义任务2
        print('危险！请赶紧撤离！')
        duration = 1000  # millisecond
        freq = 440  # Hz
        winsound.Beep(freq, duration)
        #time.sleep(1)

def main():  # 定义main函数，双线程：为了避免声音与摄像头检测冲突
    t1 = Thread(target=Camera, args=(6,))  #定义线程t1，线程任务为调用Camera函数，
                                           #task1函数的参数是6//可以是无
    
    #t2 = Thread(target=Ring)  # 定义线程t2，线程任务为调用task2函数，task2函数无参数
    t1.start()  # 开始运行主线程
    #t2.start()  # 开始运行t2线程

print('\n写在前面：这是一个高空抛物检测程序 //来自精神小伙团队[贵民大人文]\n\n指导老师：卢昌义老师\n')
print('接下来是一些简单说明：\n1、这个程序每1分钟就会进行一次模型更新以避免光线干扰,使用的过程中请不要随意移动摄像头；\n2、这个程序基于对比算法来实现高空抛物识别，因此用到的模型不多，仅仅需要每分钟的更新模型；\n3、窗口打开后按下Esc键即可退出~\n\n祝您使用愉快！这段话出现10秒后将会自动继续！\n\n      ----Check.Y (来自精神小伙！^_^)')

time.sleep(10)

if __name__ == '__main__':
    
    main()  # 调用main函数
    
